package cn.bingoo.swing.utils;

import static cn.bingoo.h2.domain.Tables.FRAMEDATA;

import java.awt.Component;
import java.awt.Container;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.JToggleButton;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.Style;

import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
import net.minidev.json.JSONStyle;
import net.minidev.json.JSONValue;

import org.jooq.impl.Factory;
import org.jooq.util.h2.H2Factory;

import cn.bingoo.h2.domain.tables.records.FramedataRecord;
import cn.bingoo.lang.Ofs;
import cn.bingoo.lang.Tuple2;

import com.google.common.base.Predicate;

public class Swings {
    public static List<Component> getAllComponents(Container c, Predicate<Component> predicate) {
        Component[] comps = c.getComponents();
        List<Component> compList = new ArrayList<Component>();
        for (Component comp : comps) {
            if (predicate.apply(comp)) {
                compList.add(comp);
            }
            if (comp instanceof Container) {
                compList.addAll(getAllComponents((Container) comp, predicate));
            }
        }

        return compList;
    }

    public static void loadPreferences(JFrame jframe) {
        String lastPerferences = getLastPerferences(jframe.getClass().getName());
        if (lastPerferences == null) {
            return;
        }

        JSONArray array = (JSONArray) JSONValue.parse(lastPerferences);
        List<Component> allComponents = getSavableComponents(jframe);
        int i = -1;
        for (Component comp : allComponents) {
            JSONObject object = (JSONObject) array.get(++i);
            if (comp instanceof JTextComponent) {
                JTextComponent textComponent = (JTextComponent) comp;
                textComponent.setText((String) object.get("_2"));
            }
            else if (comp instanceof JToggleButton) {
                JToggleButton toggleButton = (JToggleButton) comp;
                toggleButton.setSelected((Boolean) object.get("_2"));
            }
        }
    }

    public static void savePerferences(JFrame jframe) {
        List<Component> allComponents = getSavableComponents(jframe);

        List<Tuple2<String, Object>> values = null;
        values = new ArrayList<Tuple2<String, Object>>(allComponents.size());
        for (Component comp : allComponents) {
            if (comp instanceof JTextComponent) {
                JTextComponent textComponent = (JTextComponent) comp;
                values.add(Ofs.of(JTextPane.class.getName(), (Object) textComponent.getText()));
            }
            else if (comp instanceof JToggleButton) {
                JToggleButton toggleButton = (JToggleButton) comp;
                values.add(Ofs.of(JTextField.class.getName(), (Object) toggleButton.isSelected()));
            }
        }
        String jsonString = JSONValue.toJSONString(values, JSONStyle.MAX_COMPRESS);
        savePerferencesToDb(jframe.getClass().getName(), jsonString);
    }

    private static List<Component> getSavableComponents(JFrame jframe) {
        List<Component> allComponents = getAllComponents(jframe, new Predicate<Component>() {
            @Override
            public boolean apply(Component comp) {
                return comp instanceof JTextComponent || comp instanceof JToggleButton;
            }
        });
        return allComponents;
    }

    public static String getLastPerferences(String frameClassName) {
        Connection conn = null;
        try {
            conn = getConnectionWithTableAutoCreate();

            Factory create = new H2Factory(conn);
            FramedataRecord lastRecord =
                    create.selectFrom(FRAMEDATA)
                            .where(FRAMEDATA.FRAMECLASS.equal(frameClassName))
                            .orderBy(FRAMEDATA.SAVETIME.desc())
                            .limit(1)
                            .fetchOne();

            return lastRecord != null ? lastRecord.getSettings() : null;
        }
        catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
            Dbs.closeQuietly(conn);
        }
        return null;
    }

    private static Connection getConnectionWithTableAutoCreate() throws SQLException {
        Connection conn;
        DriverManager.registerDriver(new org.h2.Driver());
        conn = DriverManager.getConnection("jdbc:h2:~/bingoo-handy", "sa", "");
        if (!Dbs.tableExists(conn, "FRAMEDATA")) {
            String ddl = "CREATE TABLE FRAMEDATA(FRAMECLASS VARCHAR(100) NOT NULL, SETTINGS CLOB," +
                    " SAVETIME TIMESTAMP NOT NULL, PRIMARY KEY (FRAMECLASS,SAVETIME))";
            Dbs.execute(conn, ddl);
        }
        return conn;
    }

    public static void savePerferencesToDb(String frameClassName, String jsonString) {
        Connection conn = null;
        try {
            conn = getConnectionWithTableAutoCreate();

            Factory create = new H2Factory(conn);

            FramedataRecord newRecord = create.newRecord(FRAMEDATA);
            newRecord.setFrameclass(frameClassName);
            newRecord.setSavetime(new Timestamp(System.currentTimeMillis()));
            newRecord.setSettings(jsonString);

            newRecord.store();
        }
        catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
            Dbs.closeQuietly(conn);
        }
        // DriverManager.deregisterDriver(new org.h2.Driver());
    }

    public static void appendText(JTextComponent textPane, JCheckBox chckbxScrollLock, String str, Style style) {
        try {
            Document document = textPane.getDocument();
            document.insertString(document.getLength(), str, style);
            if (chckbxScrollLock == null || !chckbxScrollLock.isSelected()) {
                textPane.setCaretPosition(document.getLength());
            }
        }
        catch (BadLocationException e) {
            e.printStackTrace();
        }
    }

    public static void appendText(JTextComponent textPane, String str, Style style) {
        appendText(textPane, null, str, style);
    }

    public static void setText(JTextComponent textPane, String str, Style style) {
        try {
            Document document = textPane.getDocument();
            document.remove(0, document.getLength());
            document.insertString(0, str, style);
        }
        catch (BadLocationException e) {
            e.printStackTrace();
        }
    }

    public static void toClipBoard(JTextComponent textCompnent) {
        Clipboards.setClipboard(textCompnent.getText());
    }

    public static void fromClipBoard(JTextComponent textCompnent) {
        String clipboard = Clipboards.getClipboard();
        textCompnent.setText(clipboard);
    }

    public static void clearText(JTextComponent textPane) {
        try {
            Document document = textPane.getDocument();
            document.remove(0, document.getLength());
        }
        catch (BadLocationException e) {
            e.printStackTrace();
        }
    }

}
